/*
 * Copyright (c) 2024 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import { Scene } from 'arkanalyzer/lib/Scene';
import { SceneConfig, Sdk } from 'arkanalyzer/lib/Config';
import ConsoleLogger, {LOG_LEVEL, LOG_MODULE_TYPE} from 'arkanalyzer/lib/utils/logger';
import type { Logger } from 'log4js';
import { FileUtils, WriteFileMode } from './utils/FileUtils';
import { buildFileDepGraph, buildModuleDepGraph } from './builder';
import { Config, SDKConfig } from './Config';
import { Utils } from '../utils/common/Utils';

// 定义命令行参数接口
interface CommandLineArgs {
  mode: string;
  configFilePath?: string;
  projectPath?: string;
  sdkPath?: string;
  sdkName?: string;
  cSdkPaths?: string[];
  outputDir?: string;
  sourceFiles?: string[];
}

// 定义命令行选项的接口类型
interface HomeDepCliOptions {
  sdkName?: string;
  outputDir?: string;
  projectPath?: string;
  sdkPath?: string;
}

// 显示帮助信息
function showHelpAndExit(): never {
  console.error('Usage:');
  console.error('  From config file: node HomeDep.ts -m <mode> <configFilePath>');
  console.error('  From command line: node HomeDep.ts -m <mode> --projectPath <path> --sdkPath <path> [other options]');
  console.error('Modes: module-dep, file-dep-from-dir, file-dep-from-files');
  console.error('Command line options:');
  console.error('  --projectPath <path>: Project directory path');
  console.error('  --sdkPath <path>: SDK directory path');
  console.error('  --sdkName <name>: SDK name (default: "ohos")');
  console.error('  --cSdkPath <path>: C SDK directory path (can be used multiple times)');
  console.error('  --outputDir <dir>: Output directory (default: "./out")');
  console.error('  --sourceFile <path>: Source file path (required for file-dep-from-files mode, can be used multiple times)');
  process.exit(1);
}

// 解析配置文件模式的参数
function parseConfigFileMode(args: string[], mIndex: number, mode: string): CommandLineArgs {
  if (mIndex + 2 < args.length && !args[mIndex + 2].startsWith('--')) {
    const configFilePath = args[mIndex + 2];
    return { mode, configFilePath };
  }
  return parseCommandLineMode(args, mIndex, mode);
}

// 解析命令行模式的参数
function parseCommandLineMode(args: string[], mIndex: number, mode: string): CommandLineArgs {
  const cliArgs = args.slice(mIndex + 2);
  const parsedOptions = Utils.parseCliOptions(cliArgs);
  
  // 提取数组类型参数（commander默认不处理多次出现的同名参数）
  const cSdkPaths: string[] = [];
  const sourceFiles: string[] = [];
  
  for (let i = 0; i < cliArgs.length; i++) {
    if (cliArgs[i] === '--cSdkPath' && i + 1 < cliArgs.length) {
      cSdkPaths.push(cliArgs[i + 1]);
    } else if (cliArgs[i] === '--sourceFile' && i + 1 < cliArgs.length) {
      sourceFiles.push(cliArgs[i + 1]);
    }
  }
  
  const result: CommandLineArgs = { 
    mode, 
    sdkName: (parsedOptions as HomeDepCliOptions).sdkName || 'ohos',
    outputDir: (parsedOptions as HomeDepCliOptions).outputDir || './out',
    projectPath: (parsedOptions as HomeDepCliOptions).projectPath,
    sdkPath: (parsedOptions as HomeDepCliOptions).sdkPath,
    cSdkPaths,
    sourceFiles
  };
  
  validateCommandLineArgs(result);
  return result;
}

// 验证命令行参数
function validateCommandLineArgs(args: CommandLineArgs): void {
  if (!args.projectPath || !args.sdkPath) {
    console.error('Error: --projectPath and --sdkPath are required in command line mode');
    process.exit(1);
  }
  
  if (args.mode === 'file-dep-from-files' && (!args.sourceFiles || args.sourceFiles.length === 0)) {
    console.error('Error: --sourceFile parameter(s) are required for file-dep-from-files mode');
    process.exit(1);
  }
}

// 解析命令行参数
function parseArgs(): CommandLineArgs {
  const args = process.argv.slice(2);
  
  // 找到'-m'参数的位置
  const mIndex = args.indexOf('-m');
  if (mIndex === -1 || mIndex + 1 >= args.length) {
    showHelpAndExit();
  }
  
  const mode = args[mIndex + 1];
  const validModes = ['module-dep', 'file-dep-from-dir', 'file-dep-from-files'];
  if (!validModes.includes(mode)) {
    console.error(`Invalid mode: ${mode}. Valid modes are: ${validModes.join(', ')}`);
    process.exit(1);
  }
  
  return parseConfigFileMode(args, mIndex, mode);
}

// 初始化日志
function initLogger(mode: string): Logger {
  const logPath = 'out/ArkAnalyzer.log';
  const logger = ConsoleLogger.getLogger(LOG_MODULE_TYPE.TOOL, `HomeDep-${mode}`);
  ConsoleLogger.configure(logPath, LOG_LEVEL.ERROR, LOG_LEVEL.ERROR);
  return logger;
}

// 加载配置
function loadConfiguration(parsedArgs: CommandLineArgs, logger: Logger): Config {
  const config = Config.getInstance();
  
  // 根据参数类型选择加载方式
  if (parsedArgs.configFilePath) {
    // 从配置文件加载
    config.loadFromFile(parsedArgs.configFilePath);
    logger.info(`Loaded configuration from ${parsedArgs.configFilePath}`);
  } else {
    // 从命令行参数加载
    logger.info('Using configuration from command line arguments');
    
    // 设置配置值
    if (parsedArgs.projectPath) {
      config.setProjectPath(parsedArgs.projectPath);
    }
    
    if (parsedArgs.sdkPath && parsedArgs.sdkName) {
      const sdkConfig: SDKConfig = {
        name: parsedArgs.sdkName,
        path: parsedArgs.sdkPath,
        moduleName: ''
      };
      config.setSdk(sdkConfig);
    }
    
    if (parsedArgs.cSdkPaths) {
      config.setCSdkPaths(parsedArgs.cSdkPaths);
    }
    
    if (parsedArgs.outputDir) {
      config.setOutputDir(parsedArgs.outputDir);
    }
    
    if (parsedArgs.sourceFiles) {
      config.setSourceFiles(parsedArgs.sourceFiles);
    }
  }
  
  return config;
}

// 构建场景
function buildScene(config: Config, parsedArgs: CommandLineArgs): Scene {
  const projectDir = config.getProjectPath();
  const sceneConfig = new SceneConfig();
  let sdk: Sdk = config.getSdk();
  sceneConfig.getSdksObj().push(sdk);
  
  // 根据模式构建场景配置
  if (parsedArgs.mode === 'file-dep-from-files') {
    // 优先使用命令行参数中的sourceFiles，如果没有则从配置获取
    const sourceFiles = parsedArgs.sourceFiles || config.getSourceFiles();
    sceneConfig.buildFromProjectFiles('MyApplication', projectDir, sourceFiles);
  } else {
    // module-dep 和 file-dep-from-dir 都使用 buildFromProjectDir
    sceneConfig.buildFromProjectDir(projectDir);
  }
  
  // 构建场景
  const scene = new Scene();
  scene.buildSceneFromFiles(sceneConfig);
  scene.inferTypes();
  
  return scene;
}

// 分析模块依赖
function analyzeModuleDependencies(scene: Scene, config: Config, logger: Logger): void {
  const moduleDepGraphJson = config.getOutputFilePath('moduleDepGraph.json');
  const moduleDepGraphDot = config.getOutputFilePath('moduleDepGraph.dot');
  
  logger.info('Started to build module dependency graph...');
  const depGraph = buildModuleDepGraph(scene);
  
  const jsonRes = JSON.stringify(depGraph.toJson());
  FileUtils.writeToFile(moduleDepGraphJson, jsonRes, WriteFileMode.OVERWRITE);
  logger.info('Building module graph in json format has completed.');
  
  const dotRes = depGraph.dump();
  FileUtils.writeToFile(moduleDepGraphDot, dotRes, WriteFileMode.OVERWRITE);
  logger.info('Building module graph in dot format has completed.');
  
  logger.info('Building module dependency graph completed.');
}

// 分析文件依赖
function analyzeFileDependencies(scene: Scene, config: Config, mode: string, logger: Logger): void {
  const arkFiles = scene.getFiles();
  const outputSuffix = mode === 'file-dep-from-files' ? 'fileDepFromFilesGraph' : 'fileDepGraph';
  const fileDepGraphJson = config.getOutputFilePath(`${outputSuffix}.json`);
  const fileDepGraphDot = config.getOutputFilePath(`${outputSuffix}.dot`);
  
  logger.info('Started to build file dependency graph...');
  const depGraph = buildFileDepGraph(arkFiles);
  
  const jsonRes = JSON.stringify(depGraph.toJson());
  FileUtils.writeToFile(fileDepGraphJson, jsonRes, WriteFileMode.OVERWRITE);
  logger.info('Building dependency graph in json format has completed.');
  
  const dotRes = depGraph.dump();
  FileUtils.writeToFile(fileDepGraphDot, dotRes, WriteFileMode.OVERWRITE);
  logger.info('Building dependency graph in dot format has completed.');
  
  logger.info('Building file dependency graph completed.');
}

async function main(): Promise<void> {
  const parsedArgs = parseArgs();
  const { mode } = parsedArgs;
  const logger = initLogger(mode);
  
  try {
    const config = loadConfiguration(parsedArgs, logger);
    const scene = buildScene(config, parsedArgs);
    
    if (mode === 'module-dep') {
      analyzeModuleDependencies(scene, config, logger);
    } else {
      analyzeFileDependencies(scene, config, mode, logger);
    }
  } catch (error) {
    logger.error(`Error during execution: ${error instanceof Error ? error.message : String(error)}`);
    process.exit(1);
  }
}

// 执行主函数
main();